using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using HengTong.Model._Admin;
using HengTong.Model.Db;
using HengTong.Model.Interfaces;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using TiaoTaoHelper.Wtm.Models;
using WalkingTec.Mvvm.Core;
using System.Collections.Concurrent;
using HengTong.Model.Db.Hr.Bill;
using HengTong.Model.Db.System;
using TiaoTaoHelper.Wtm.Interfaces;

namespace HengTong.Model.Extension
{
    public static class DataPrivilegeExtension
    {
        // 用于跟踪缓存键的集合
        private static readonly ConcurrentDictionary<string, HashSet<string>> UserCacheKeys = new();
        private static readonly object LockObject = new object();
        
        /// <summary>
        /// 检查数据权限
        /// </summary>
        /// <typeparam name="T">查询实体类型</typeparam>
        /// <param name="baseQuery">原始查询</param>
        /// <param name="context">WTM上下文</param>
        /// <returns>添加权限过滤后的查询</returns>
        public static IQueryable<T> CheckDataPrivilege<T>(this IQueryable<T> baseQuery, WTMContext context) 
            where T : class, IDataPrivilegeEntity
        {
            if (context?.LoginUserInfo == null)
            {
                // 未登录用户无权限
                return baseQuery.Where(x => false);
            }

            var user = context.LoginUserInfo;
            var dc = context.DC;
            
            // 超级管理员跳过权限检查
            if (user.Roles?.Any(r => r.RoleCode == "001") == true)
            {
                return baseQuery;
            }
            
            // 如果 T 实现了 IBill 接口，添加草稿状态权限控制
            if (typeof(IBill).IsAssignableFrom(typeof(T)) && typeof(T) != typeof(SysPersonRepairBill))
            {
                // 草稿状态的单据仅创建者可见
                baseQuery = baseQuery.Where(x => 
                    !((IBill)x).BillStatus.HasValue || 
                    ((IBill)x).BillStatus.Value != BillStatus.草稿 || 
                    x.CreateBy == user.ITCode);
            }
            
            // 获取用户的权限信息
            var userPrivileges = GetUserDataPrivileges(user, dc, typeof(T).FullName, context);
            
            // 构建查询条件
            var predicate = BuildPrivilegePredicate<T>(userPrivileges, user, dc);
            
            return baseQuery.Where(predicate);
        }
        
        /// <summary>
        /// 获取用户的数据权限配置
        /// </summary>
        private static List<SysDataPrivilege> GetUserDataPrivileges(LoginUserInfo user, IDataContext dc, string entityType, WTMContext context)
        {
            var scope = context.ServiceProvider.CreateScope();
            var memoryCache = scope.ServiceProvider.GetRequiredService<IMemoryCache>();
            
            var cacheKey = $"DataPrivilege_{user.ITCode}_{entityType}";
            
#if !DEBUG
            // 在非DEBUG模式下才使用缓存
            if (memoryCache.TryGetValue<List<SysDataPrivilege>>(cacheKey, out var cached))
            {
                scope.Dispose();
                return cached;
            }
#endif
            
            var privileges = new List<SysDataPrivilege>();
            
            // 获取用户的所有岗位
            var userPositions = GetUserPositions(Guid.Parse(user.UserId), dc, memoryCache);
            
            // 查询权限配置
            var query = dc.Set<SysDataPrivilege>()
                .Where(p => p.EntityType == entityType && p.IsEnabled);
            
            // 角色权限
            if (user.Roles?.Any() == true)
            {
                var roleIds = user.Roles.Select(r => r.ID).ToList();
                var rolePrivileges = query
                    .Where(p => p.TargetType == DataPrivilegeTargetType.角色 && roleIds.Contains(p.TargetId))
                    .ToList();
                privileges.AddRange(rolePrivileges);
            }
            
            // 岗位权限
            if (userPositions?.Any() == true)
            {
                var positionIds = userPositions.Select(p => p.JobPositionId).ToList();
                var positionPrivileges = query
                    .Where(p => p.TargetType == DataPrivilegeTargetType.岗位 && positionIds.Contains(p.TargetId))
                    .ToList();
                privileges.AddRange(positionPrivileges);
            }
            
            // 部门权限
            if (user.Groups?.Any() == true)
            {
                var groupIds = user.Groups.Select(g => g.ID).ToList();
                var groupPrivileges = query
                    .Where(p => p.TargetType == DataPrivilegeTargetType.部门 && groupIds.Contains(p.TargetId))
                    .ToList();
                privileges.AddRange(groupPrivileges);
            }
            
            // 如果没有配置权限，使用默认权限
            if (!privileges.Any())
            {
                privileges.AddRange(GetDefaultPrivileges(user, entityType, dc, memoryCache));
            }
            
#if !DEBUG
            // 在非DEBUG模式下才设置缓存
            memoryCache.Set(cacheKey, privileges, TimeSpan.FromMinutes(5));
            
            // 记录缓存键
            TrackCacheKey(Guid.Parse(user.UserId), cacheKey);
#endif
            
            scope.Dispose();
            return privileges;
        }
        
        /// <summary>
        /// 获取用户岗位信息（带缓存）
        /// </summary>
        private static List<SysUserJobPosition> GetUserPositions(Guid userId, IDataContext dc, IMemoryCache memoryCache)
        {
            var cacheKey = $"UserPositions_{userId}";
            
            if (memoryCache.TryGetValue<List<SysUserJobPosition>>(cacheKey, out var cached))
            {
                return cached;
            }
            
            var positions = dc.Set<SysUserJobPosition>()
                .Include(p => p.JobPosition)
                .Where(p => p.UserId == userId)
                .ToList();
            
            memoryCache.Set(cacheKey, positions, TimeSpan.FromMinutes(10));
            
            return positions;
        }
        
        /// <summary>
        /// 获取默认权限配置列表
        /// </summary>
        private static List<SysDataPrivilege> GetDefaultPrivileges(LoginUserInfo user, string entityType, IDataContext dc, IMemoryCache memoryCache)
        {
            var privileges = new List<SysDataPrivilege>();
            var userPositions = GetUserPositions(Guid.Parse(user.UserId), dc, memoryCache);
            
            if (userPositions?.Any() == true)
            {
                // 为每个岗位创建对应的权限配置
                foreach (var position in userPositions)
                {
                    if(position.JobPositionId == null) continue;
                    var privilege = new SysDataPrivilege
                    {
                        EntityType = entityType,
                        TargetType = DataPrivilegeTargetType.岗位,
                        TargetId = position.JobPositionId.Value,
                        Priority = -1  // 默认权限优先级最低
                    };
                    
                    // 如果是管理岗位，可以查看本部门及子部门数据
                    if (position.JobPosition.IsManager)
                    {
                        privilege.Scope = DataPrivilegeScope.本部门及下级;
                        privilege.Priority = 0;  // 管理岗位优先级稍高
                    }
                    else
                    {
                        // 普通岗位只能查看自己创建的数据
                        privilege.Scope = DataPrivilegeScope.仅本人;
                    }
                    
                    privileges.Add(privilege);
                }
            }
            
            // 如果没有任何岗位，默认只能查看自己的数据
            if (!privileges.Any())
            {
                privileges.Add(new SysDataPrivilege
                {
                    EntityType = entityType,
                    TargetType = DataPrivilegeTargetType.岗位,
                    Scope = DataPrivilegeScope.仅本人,
                    Priority = -1
                });
            }
            
            return privileges;
        }
        
        /// <summary>
        /// 构建权限查询条件
        /// </summary>
        private static Expression<Func<T, bool>> BuildPrivilegePredicate<T>(
            List<SysDataPrivilege> privileges, 
            LoginUserInfo user, 
            IDataContext dc) where T : class, IDataPrivilegeEntity
        {
            if (!privileges.Any())
            {
                // 无权限
                return x => false;
            }
            
            var parameter = Expression.Parameter(typeof(T), "x");
            var predicates = new List<Expression>();
            
            // 按优先级分组处理权限
            var groupedPrivileges = privileges.GroupBy(p => p.Priority).OrderByDescending(g => g.Key);
            
            foreach (var group in groupedPrivileges)
            {
                var groupPredicates = new List<Expression>();
                
                foreach (var privilege in group)
                {
                    Expression predicate = null;
                    
                    switch (privilege.Scope)
                    {
                        case DataPrivilegeScope.仅本人:
                            // 仅本人：CreateBy = user.ITCode
                            var createByProperty = Expression.Property(parameter, "CreateBy");
                            var userCode = Expression.Constant(user.ITCode);
                            predicate = Expression.Equal(createByProperty, userCode);
                            break;
                            
                        case DataPrivilegeScope.本部门:
                            // 本部门：根据岗位所属部门判断
                            predicate = BuildDepartmentPredicate<T>(privilege, parameter, dc, user);
                            break;
                            
                        case DataPrivilegeScope.本部门及下级:
                            // 本部门及下级：根据岗位所属部门及其子部门判断
                            predicate = BuildDepartmentAndSubordinatePredicate<T>(privilege, parameter, dc, user);
                            break;
                            
                        case DataPrivilegeScope.全部:
                            // 全部权限
                            predicate = Expression.Constant(true);
                            break;
                            
                        case DataPrivilegeScope.自定义:
                            // 自定义条件（需要动态解析）
                            if (!string.IsNullOrEmpty(privilege.CustomCondition))
                            {
                                predicate = ParseCustomCondition<T>(privilege.CustomCondition, parameter, user);
                            }
                            break;
                    }
                    
                    if (predicate != null)
                    {
                        groupPredicates.Add(predicate);
                    }
                }
                
                // 同一优先级的权限用OR连接
                if (groupPredicates.Any())
                {
                    var groupPredicate = groupPredicates.Count == 1 
                        ? groupPredicates[0] 
                        : groupPredicates.Aggregate(Expression.OrElse);
                    predicates.Add(groupPredicate);
                }
            }
            
            // 不同优先级的权限用OR连接（取最宽松的权限）
            var finalPredicate = predicates.Any() 
                ? predicates.Aggregate(Expression.OrElse) 
                : Expression.Constant(false);
            
            return Expression.Lambda<Func<T, bool>>(finalPredicate, parameter);
        }
        
        /// <summary>
        /// 构建部门权限查询条件（包括本人创建的数据）
        /// </summary>
        private static Expression BuildDepartmentPredicate<T>(
            SysDataPrivilege privilege,
            ParameterExpression parameter,
            IDataContext dc,
            LoginUserInfo user) where T : class, IDataPrivilegeEntity
        {
            List<Guid?> groupIds = new List<Guid?>();

            if (privilege.TargetType == DataPrivilegeTargetType.岗位)
            {
                // 根据岗位ID获取部门ID
                var groupId = dc.Set<SysJobPosition>()
                    .Where(p => p.ID == privilege.TargetId)
                    .Select(e => e.GroupId)
                    .FirstOrDefault();
                if (groupId.HasValue)
                {
                    groupIds.Add(groupId);
                }
            }
            else if (privilege.TargetType == DataPrivilegeTargetType.角色)
            {
                // 检查用户是否拥有该角色
                if (user.Roles.Any(x => x.ID == privilege.TargetId))
                {
                    groupIds = dc.Set<SysUserJobPosition>()
                        .Where(e => e.UserId == Guid.Parse(user.UserId))
                        .Where(e => e.JobPosition.Roles.Any(r => r.RoleId == privilege.TargetId))
                        .Select(e => e.JobPosition.GroupId)
                        .ToList();
                }
            }
            else if (privilege.TargetType == DataPrivilegeTargetType.部门)
            {
                // 只处理当前权限配置的部门
                if (user.Groups.Any(x => x.ID == privilege.TargetId))
                {
                    groupIds.Add(privilege.TargetId);
                }
            }

            if (!groupIds.Any())
            {
                return Expression.Constant(false);
            }
            // 构建部门条件
            var groupIdProperty = Expression.Property(parameter, "GroupId");
            var departmentCondition = BuildInExpression(groupIdProperty, groupIds);

            // 构建"本人创建"条件
            var createByProperty = Expression.Property(parameter, "CreateBy");
            var userCode = Expression.Constant(user.ITCode);
            var selfCondition = Expression.Equal(createByProperty, userCode);

            // 部门条件 OR 本人条件
            return Expression.OrElse(departmentCondition, selfCondition);
        }
        /// <summary>
        /// 构建部门及子部门权限查询条件（包括本人创建的数据）
        /// </summary>
        private static Expression BuildDepartmentAndSubordinatePredicate<T>(
            SysDataPrivilege privilege, 
            ParameterExpression parameter, 
            IDataContext dc,
            LoginUserInfo user) where T : class, IDataPrivilegeEntity
        {
            List<Guid?> groupIds = new List<Guid?>();
            if (privilege.TargetType == DataPrivilegeTargetType.岗位)
            {
                // 根据岗位ID获取部门ID
                var groupId = dc.Set<SysJobPosition>()
                    .Where(p => p.ID == privilege.TargetId)
                    .Select(e => e.GroupId)
                    .FirstOrDefault();
                if (groupId.HasValue)
                {
                    groupIds.Add(groupId);
                }
            }
            else if (privilege.TargetType == DataPrivilegeTargetType.角色)
            {
                // 检查用户是否拥有该角色
                if (user.Roles.Any(x => x.ID == privilege.TargetId))
                {
                    groupIds = dc.Set<SysUserJobPosition>()
                        .Where(e => e.UserId == Guid.Parse(user.UserId))
                        .Where(e => e.JobPosition.Roles.Any(r => r.RoleId == privilege.TargetId))
                        .Select(e => e.JobPosition.GroupId)
                        .ToList();
                }
            }
            else if (privilege.TargetType == DataPrivilegeTargetType.部门)
            {
                // 只处理当前权限配置的部门
                if (user.Groups.Any(x => x.ID == privilege.TargetId))
                {
                    groupIds.Add(privilege.TargetId);
                }
            }

            if (!groupIds.Any())
            {
                return Expression.Constant(false);
            }
            
            
            
            // 获取部门及其所有子部门
            var allGroupIds = GetDepartmentAndSubordinates(groupIds, dc);
            var groupIdProperty = Expression.Property(parameter, "GroupId");
            
            // 构建部门范围条件
            var departmentCondition = BuildInExpression(groupIdProperty, allGroupIds);
            
            // 构建"本人创建"条件
            var createByProperty = Expression.Property(parameter, "CreateBy");
            var userCode = Expression.Constant(user.ITCode);
            var selfCondition = Expression.Equal(createByProperty, userCode);
            
            // 部门条件 OR 本人条件
            return Expression.OrElse(departmentCondition, selfCondition);
        }
        
        /// <summary>
        /// 构建 IN 表达式
        /// </summary>
        private static Expression BuildInExpression(MemberExpression property, List<Guid?> values)
        {
            if (!values.Any())
            {
                return Expression.Constant(false);
            }
            
            var method = typeof(List<Guid?>).GetMethod("Contains", new[] { typeof(Guid?) });
            if (method == null)
            {
                throw new InvalidOperationException("Unable to find Contains method on List<Guid?>");
            }
            
            var list = Expression.Constant(values);
            return Expression.Call(list, method, property);
        }
        
        /// <summary>
        /// 获取部门及所有下级部门
        /// </summary>
        private static List<Guid?> GetDepartmentAndSubordinates(List<Guid?> groupIds, IDataContext dc)
        {
            if (groupIds == null || !groupIds.Any())
            {
                return new List<Guid?>();
            }
            
            var allGroups = new List<Guid?>(groupIds);
            var queue = new Queue<Guid?>(groupIds);
            
            while (queue.Count > 0)
            {
                var currentId = queue.Dequeue();
                if (!currentId.HasValue) continue;
                
                var children = dc.Set<SysGroup>()
                    .Where(g => g.ParentId == currentId)
                    .Select(g => (Guid?)g.ID)
                    .ToList();
                
                foreach (var child in children)
                {
                    if (!allGroups.Contains(child))
                    {
                        allGroups.Add(child);
                        queue.Enqueue(child);
                    }
                }
            }
            
            return allGroups;
        }
        
        /// <summary>
        /// 解析自定义条件（简化版本）
        /// </summary>
        private static Expression ParseCustomCondition<T>(string condition, ParameterExpression parameter, LoginUserInfo user)
        {
            // 这里可以实现一个简单的条件解析器
            // 例如支持 "Status = 1 AND GroupId = {CurrentGroupId}" 这样的条件
            // 实际项目中可以使用更复杂的表达式解析库
            
            // 暂时返回 true
            return Expression.Constant(true);
        }
        
        /// <summary>
        /// 跟踪缓存键
        /// </summary>
        private static void TrackCacheKey(Guid userId, string cacheKey)
        {
            lock (LockObject)
            {
                if (!UserCacheKeys.ContainsKey(userId.ToString()))
                {
                    UserCacheKeys[userId.ToString()] = new HashSet<string>();
                }
                UserCacheKeys[userId.ToString()].Add(cacheKey);
            }
        }
        
        /// <summary>
        /// 清除用户权限缓存
        /// </summary>
        public static void ClearUserPrivilegeCache(this WTMContext context, Guid userId)
        {
            var scope = context.ServiceProvider.CreateScope();
            var memoryCache = scope.ServiceProvider.GetRequiredService<IMemoryCache>();
            
            // 清除用户相关的所有缓存键
            lock (LockObject)
            {
                if (UserCacheKeys.TryGetValue(userId.ToString(), out var keys))
                {
                    foreach (var key in keys)
                    {
                        memoryCache.Remove(key);
                    }
                    UserCacheKeys.TryRemove(userId.ToString(), out _);
                }
            }
            
            memoryCache.Remove($"UserPositions_{userId}");
            
            scope.Dispose();
        }
        
        /// <summary>
        /// 清除所有用户权限缓存
        /// </summary>
        public static void ClearAllUserPrivilegeCache(this WTMContext context)
        {
            var scope = context.ServiceProvider.CreateScope();
            var memoryCache = scope.ServiceProvider.GetRequiredService<IMemoryCache>();
            
            lock (LockObject)
            {
                foreach (var userKeys in UserCacheKeys.Values)
                {
                    foreach (var key in userKeys)
                    {
                        memoryCache.Remove(key);
                    }
                }
                UserCacheKeys.Clear();
            }
            
            scope.Dispose();
        }
    }
}